﻿// Copyright (c) 2009, Heiko Wundram (modelnine@h8me.eu).
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
// conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
//   in the documentation and/or other materials provided with the distribution.
// * Neither the name of Heiko Wundram (h8me.eu) nor the names of its contributors may be used to endorse or promote products
//   derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using eu.h8me.Parsing.ParserLib;

namespace eu.h8me.Parsing.LexerLib {

    // Regular expression parser helper.
    internal class RegExParser {

        // Data.
        private static RegExParser SINGLETON;
        private Grammar _Grammar = new Grammar();

        // Constructor (which initializes the grammar for regular expressions).
        private RegExParser() {
            // Base expression.
            GrammarExpr();
            GrammarNameExpr();
            GrammarOrAndExpr();
            GrammarOperand();
            GrammarRepeatCount();
            GrammarSimpleOperand();
            GrammarCharGroups();
            GrammarCharGroupFlags();
            GrammarChars();
            GrammarNameNumber();

            // Try to initialize grammar from stream.
            IEnumerable<string> warnings;
            try {
                // Finalize the grammar from stream.
                using( Stream s = Assembly.GetAssembly(typeof(RegExParser)).GetManifestResourceStream("eu.h8me.Parsing.RegExParser.Grammar.xml") )
                    warnings = _Grammar.Finish("expr", s);
            } catch( NullReferenceException ) {
                // Finalize grammar as is (stream failed to load).
                warnings = _Grammar.Finish("expr");
            }
        }

        // Build expression grammar.
        private void GrammarExpr() {
            // Base expression.
            _Grammar["expr"].Add(_Grammar["orexpr"] + _Grammar["exprflags?"]).ReduceEvent += FinishTree;
            _Grammar["expr"].Add(_Grammar["nameexprflag"] + _Grammar["nameexpr"]).ReduceEvent += Production.Fetch(1);

            // Possible expression flags.
            _Grammar["exprflags?"].Add(_Grammar.Epsilon).ReduceEvent += AttachTreeFlag;
            _Grammar["exprflags?"].Add(_Grammar["flags"] + _Grammar["exprflags"]).ReduceEvent += Production.Fetch(1);

            // Expression flags.
            _Grammar["exprflags"].Add(_Grammar.Epsilon).ReduceEvent += AttachTreeFlag;
            _Grammar["exprflags"].Add(_Grammar["exprflags"] + _Grammar["exprflag"]).ReduceEvent += AttachTreeFlag;
            _Grammar["exprflags"].Add(_Grammar["exprflags"] + _Grammar["nameflag"]).ReduceEvent += AttachTreeFlag;

            // Expression flag.
            _Grammar["exprflag"].Add(_Grammar["-"]).ReduceEvent += ProcessExpressionFlag;
            _Grammar["exprflag"].Add(_Grammar["+"] + _Grammar["("] + _Grammar["nameexpr"] + _Grammar[")"]).ReduceEvent += ProcessExpressionFlag;
        }

        // Finish a tree.
        private object FinishTree(ParseState state, Token[] symbols) {
            // Finish the tree by applying expression flags.
            Tree tree = (Tree)symbols[0].Data;
            foreach( Tree.Process cb in (List<Tree.Process>)symbols[1].Data )
                tree = cb(tree);

            // Return finalized tree.
            tree.Finish();
            return tree;
        }

        // Parse and attach an expression flag.
        private object AttachTreeFlag(ParseState state, Token[] symbols) {
            // Check where we're called.
            List<Tree.Process> rv;
            if( symbols.Length > 0 ) {
                // Attach flag to list.
                rv = new List<Tree.Process>((List<Tree.Process>)symbols[0].Data);
                rv.Add((Tree.Process)symbols[1].Data);
            } else
                // Build empty list.
                rv = new List<Tree.Process>();

            // Return new list.
            return rv;
        }

        // Process expression flag.
        private object ProcessExpressionFlag(ParseState state, Token[] symbols) {
            // Check symbol.
            switch( (char)symbols[0].Data ) {

                case '-':
                    // Match at beginning of line (i.e., after a \n).
                    return new Tree.Process(Tree.AtNewLine);

                case '+':
                    // Match trailing data.
                    return new Tree.Process(Tree.Trailing((Tree)symbols[2].Data));

            }

            // We can't/shouldn't get here.
            throw new ArgumentException("Illegal flag found during processing, grammar error?");
        }

        // Name expression.
        private void GrammarNameExpr() {
            // Build name expression.
            _Grammar["nameexpr"].Add(_Grammar["orexpr"] + _Grammar["nameflags?"]).ReduceEvent += FinishTree;

            // Possible name flags.
            _Grammar["nameflags?"].Add(_Grammar.Epsilon).ReduceEvent += AttachTreeFlag;
            _Grammar["nameflags?"].Add(_Grammar["flags"] + _Grammar["nameflags"]).ReduceEvent += Production.Fetch(1);

            // Name flags.
            _Grammar["nameflags"].Add(_Grammar.Epsilon).ReduceEvent += AttachTreeFlag;
            _Grammar["nameflags"].Add(_Grammar["nameflags"] + _Grammar["nameflag"]).ReduceEvent += AttachTreeFlag;

            // Name flag.
            _Grammar["nameflag"].Add(_Grammar["alpha"]).ReduceEvent += ProcessNameFlag;
        }

        // Process a name flag.
        private object ProcessNameFlag(ParseState state, Token[] symbols) {
            // Switch on type.
            switch( (char)symbols[0].Data ) {

                case 'c':
                    // Ignore case on match everywhere.
                    return new Tree.Process(Tree.IgnoreCase);

            }

            // Flag failed to process.
            throw new ArgumentException("Invalid flag for expression");
        }

        // Or/and expressions.
        private void GrammarOrAndExpr() {
            // Split expression.
            _Grammar["orexpr"].Add(_Grammar["andexpr"]);
            _Grammar["orexpr"].Add(_Grammar["orexpr"] + _Grammar["|"] + _Grammar["andexpr"]).ReduceEvent += MergeNodes;

            // Chain expression.
            _Grammar["andexpr"].Add(_Grammar.Epsilon).ReduceEvent += ChainNodes;
            _Grammar["andexpr"].Add(_Grammar["andexpr"] + _Grammar["op"]).ReduceEvent += ChainNodes;
        }

        // Node merging.
        private object MergeNodes(ParseState state, Token[] symbols) {
            // Merge the second tree to the first.
            return (Tree)symbols[0].Data | (Tree)symbols[2].Data;
        }

        // Node chaining.
        private object ChainNodes(ParseState state, Token[] symbols) {
            // Check whether we have two trees.
            if( symbols.Length == 0 )
                // Create a new, empty tree on empty input.
                return new Tree();

            // Yes, attach trailing to initial tree.
            return (Tree)symbols[0].Data + (Tree)symbols[1].Data;
        }

        // Operand expressions.
        private void GrammarOperand() {
            // Operand.
            _Grammar["op"].Add(_Grammar["simpleop"]);
            _Grammar["op"].Add(_Grammar["simpleop"] + _Grammar["*"]).ReduceEvent += RepeatNode;
            _Grammar["op"].Add(_Grammar["simpleop"] + _Grammar["+"]).ReduceEvent += RepeatNode;
            _Grammar["op"].Add(_Grammar["simpleop"] + _Grammar["?"]).ReduceEvent += RepeatNode;
        }

        // Zero or more node repetition.
        private object RepeatNode(ParseState state, Token[] symbols) {
            // Dispatch on repetition char.
            switch( (char)symbols[1].Data ) {

                case '*':
                    // Zero or more repetition.
                    return ( (Tree)symbols[0].Data ).ZeroOrMore();

                case '+':
                    // One or more repetition.
                    return ( (Tree)symbols[0].Data ).OneOrMore();

                case '?':
                    // Zero or one repetition.
                    return ( (Tree)symbols[0].Data ).ZeroOrOne();

            }

            // We can't/shouldn't get here.
            throw new ArgumentException("Grammar error, unexpected repetition symbol found");
        }

        // Simple operands.
        private void GrammarSimpleOperand() {
            // Simple operand.
            _Grammar["simpleop"].Add(_Grammar["("] + _Grammar["orexpr"] + _Grammar[")"]).ReduceEvent += Production.Fetch(1);
            _Grammar["simpleop"].Add(_Grammar["."]).ReduceEvent += BuildAnyNode;
            _Grammar["simpleop"].Add(_Grammar["simpleop"] + _Grammar["{"] + _Grammar["repcnt"] + _Grammar["}"]).ReduceEvent += BuildCountRepeatNode;
            _Grammar["simpleop"].Add(_Grammar["{"] + _Grammar["name"] + _Grammar["namedef?"] + _Grammar["nameflags?"] + _Grammar["}"]).ReduceEvent += BuildNamedNode;
            _Grammar["simpleop"].Add(_Grammar["["] + _Grammar["chargrps"] + _Grammar["chargrpflags?"] + _Grammar["]"]).ReduceEvent += BuildCharRangeNode;
            _Grammar["simpleop"].Add(_Grammar["simpleopchar"]).ReduceEvent += BuildCharNode;

            // Name definition included in named group.
            _Grammar["namedef?"].Add(_Grammar.Epsilon);
            _Grammar["namedef?"].Add(_Grammar["("] + _Grammar["nameexpr"] + _Grammar[")"]).ReduceEvent += Production.Fetch(1);
        }

        // Build any node.
        private object BuildAnyNode(ParseState state, Token[] symbols) {
            // Return new char range for any.
            return new Tree(CharRange.ANY);
        }

        // Count node repetition.
        private object BuildCountRepeatNode(ParseState state, Token[] symbols) {
            // Repeat the current tree multiple times.
            return ( (Tree)symbols[0].Data ).Repeat((RepeatCount)symbols[2].Data);
        }

        // Fetch name.
        private object BuildNamedNode(ParseState state, Token[] symbols) {
            // Check whether we're trying to define a node.
            Tree tree;
            if( symbols[2].Data != null )
                // Yes, this is a node definition, store it in name cache and yield definition.
                ( (Dictionary<string, Tree>)state.Parser.Tag )[(string)symbols[1].Data] = tree = (Tree)symbols[2].Data;
            else if( !( (Dictionary<string, Tree>)state.Parser.Tag ).TryGetValue((string)symbols[1].Data, out tree) )
                // Failed to fetch existing named node.
                throw new ArgumentException("Invalid named regex group");

            // Finish the node by applying expression flags for this instantiation.
            List<Tree.Process> flags = (List<Tree.Process>)symbols[3].Data;
            if( flags.Count > 0 ) {
                // Apply the flags (which in turn all make a copy).
                foreach( Tree.Process cb in flags )
                    tree = cb(tree);
            } else
                // Just make a copy (no flags to apply).
                tree = tree.Clone(null, null);

            // Return clone of node for use here.
            return tree;
        }

        // Build a char group node.
        private object BuildCharRangeNode(ParseState state, Token[] symbols) {
            // Finalize char range using group flags.
            CharRange range = (CharRange)symbols[1].Data;
            foreach( CharRange.Process cb in (List<CharRange.Process>)symbols[2].Data )
                range = cb(range);

            // Return new tree built on contained range.
            return new Tree(range);
        }

        // Build char node.
        private object BuildCharNode(ParseState state, Token[] symbols) {
            // Return new tree built on char.
            return new Tree(new CharRange((char)symbols[0].Data));
        }

        // Repeat count elements.
        private void GrammarRepeatCount() {
            // Repetition count.
            _Grammar["repcnt"].Add(_Grammar["nums"]).ReduceEvent += RepeatFromToCount;
            _Grammar["repcnt"].Add(_Grammar["nums"] + _Grammar["-"]).ReduceEvent += RepeatFromCount;
            _Grammar["repcnt"].Add(_Grammar["-"] + _Grammar["nums"]).ReduceEvent += RepeatToCount;
            _Grammar["repcnt"].Add(_Grammar["nums"] + _Grammar["-"] + _Grammar["nums"]).ReduceEvent += RepeatFromToCount;
        }

        // Repeat from count node count.
        private object RepeatFromCount(ParseState state, Token[] symbols) {
            // Return object representing the from count.
            return new RepeatCount((int)symbols[0].Data);
        }

        // Repeat to count node count.
        private object RepeatToCount(ParseState state, Token[] symbols) {
            // Fetch count and check.
            int to = (int)symbols[1].Data;
            if( to == 0 )
                throw new ArgumentException("Illegal to repeat count, is zero");

            // Return new repeat object.
            return new RepeatCount(0, to);
        }

        // Repeat from/to count node count.
        private object RepeatFromToCount(ParseState state, Token[] symbols) {
            // Check whether we have from and to.
            int from;
            int to;
            if( symbols.Length > 1 ) {
                // Fetch them both and check range.
                from = (int)symbols[0].Data;
                to = (int)symbols[2].Data;
                if( from > to )
                    throw new ArgumentException("Illegal repeat count, from > to");
            } else
                // Is the simple case with a fixed repeat count.
                from = to = (int)symbols[0].Data;

            // Check whether to has propercount (can't have zero repeats).
            if( to == 0 )
                throw new ArgumentException("Illegal to repeat count, is zero");
            return new RepeatCount(from, to);
        }

        // Character group grammar.
        private void GrammarCharGroups() {
            // Character groups.
            _Grammar["chargrps"].Add(_Grammar["chargrp"]);
            _Grammar["chargrps"].Add(_Grammar["chargrps"] + _Grammar["chargrp"]).ReduceEvent += MergeCharRange;

            // Character group.
            _Grammar["chargrp"].Add(_Grammar["chargrpchar"]).ReduceEvent += BuildCharRange;
            _Grammar["chargrp"].Add(_Grammar["chargrpchar"] + _Grammar["-"] + _Grammar["chargrpchar"]).ReduceEvent += BuildCharRange;
        }

        // Merge character range.
        private object MergeCharRange(ParseState state, Token[] symbols) {
            // Merge the two ranges to form a new range.
            return (CharRange)symbols[0].Data | (CharRange)symbols[1].Data;
        }

        // Build character group.
        private object BuildCharRange(ParseState state, Token[] symbols) {
            // Check token length (for production).
            if( symbols.Length > 1 ) {
                // Is a range, check range.
                if( (char)symbols[0].Data > (char)symbols[2].Data )
                    throw new ArgumentException("Invalid character range, would be empty");
                return new CharRange((char)symbols[0].Data, (char)symbols[2].Data);
            }

            // Is a single character; just return char.
            return new CharRange((char)symbols[0].Data);
        }

        // Character group flags.
        private void GrammarCharGroupFlags() {
            // Possible character group flags.
            _Grammar["chargrpflags?"].Add(_Grammar.Epsilon).ReduceEvent += AttachCharRangeFlag;
            _Grammar["chargrpflags?"].Add(_Grammar["flags"] + _Grammar["chargrpflags"]).ReduceEvent += Production.Fetch(1);

            // Character group flags.
            _Grammar["chargrpflags"].Add(_Grammar.Epsilon).ReduceEvent += AttachCharRangeFlag;
            _Grammar["chargrpflags"].Add(_Grammar["chargrpflags"] + _Grammar["chargrpflag"]).ReduceEvent += AttachCharRangeFlag;

            // Character group flag.
            _Grammar["chargrpflag"].Add(_Grammar["alpha"]).ReduceEvent += ProcessCharRangeFlag;
        }

        // Parse and attach a char group flag.
        private object AttachCharRangeFlag(ParseState state, Token[] symbols) {
            // Check where we're called.
            List<CharRange.Process> rv;
            if( symbols.Length > 0 ) {
                // Attach flag to list.
                rv = new List<CharRange.Process>((List<CharRange.Process>)symbols[0].Data);
                rv.Add((CharRange.Process)symbols[1].Data);
            } else
                // Initialize new list.
                rv = new List<CharRange.Process>();

            // Return list.
            return rv;
        }

        // Process a character group flag.
        private object ProcessCharRangeFlag(ParseState state, Token[] symbols) {
            // Switch on type.
            switch( (char)symbols[0].Data ) {

                case 'c':
                    // Ignore case on match.
                    return new CharRange.Process(CharRange.IgnoreCase);

                case 'i':
                    // Invert it.
                    return new CharRange.Process(CharRange.Invert);

            }

            // Flag failed to process.
            throw new ArgumentException("Invalid flag for character group");
        }

        // Character set grammars.
        private void GrammarChars() {
            // Simple operand chars.
            _Grammar["simpleopchar"].Add(_Grammar["basechar"]);
            _Grammar["simpleopchar"].Add(_Grammar["-"]);
            _Grammar["simpleopchar"].Add(_Grammar["]"]);

            // Character group character.
            _Grammar["chargrpchar"].Add(_Grammar["basechar"]);
            _Grammar["chargrpchar"].Add(_Grammar["."]);
            _Grammar["chargrpchar"].Add(_Grammar["("]);
            _Grammar["chargrpchar"].Add(_Grammar[")"]);
            _Grammar["chargrpchar"].Add(_Grammar["["]);
            _Grammar["chargrpchar"].Add(_Grammar["{"]);
            _Grammar["chargrpchar"].Add(_Grammar["}"]);
            _Grammar["chargrpchar"].Add(_Grammar["|"]);
            _Grammar["chargrpchar"].Add(_Grammar["*"]);
            _Grammar["chargrpchar"].Add(_Grammar["+"]);
            _Grammar["chargrpchar"].Add(_Grammar["?"]);

            // Character base. No need to declare specific productions here.
            _Grammar["basechar"].Add(_Grammar["char"]);
            _Grammar["basechar"].Add(_Grammar["alpha"]);
            _Grammar["basechar"].Add(_Grammar["num"]);
            _Grammar["basechar"].Add(_Grammar["hexesc"]);
            _Grammar["basechar"].Add(_Grammar["uniesc"]);
            _Grammar["basechar"].Add(_Grammar["octesc"]);

            // Escape sequence types.
            _Grammar["hexesc"].Add(_Grammar["hexescintro"] + _Grammar["hexnum"] + _Grammar["hexnum"]).ReduceEvent += HexEscape;
            _Grammar["uniesc"].Add(_Grammar["uniescintro"] + _Grammar["hexnum"] + _Grammar["hexnum"] + _Grammar["hexnum"] + _Grammar["hexnum"]).ReduceEvent += HexEscape;
            _Grammar["octesc"].Add(_Grammar["octescintro"] + _Grammar["num"] + _Grammar["num"]).ReduceEvent += OctEscape;

            // Hex number. No need to declare specific productions here.
            _Grammar["hexnum"].Add(_Grammar["alpha"]);
            _Grammar["hexnum"].Add(_Grammar["num"]);
        }

        // Hexadecimal escape processing.
        private object HexEscape(ParseState state, Token[] symbols) {
            // Loop over symbols, excluding first (which is the escape intro).
            int rv = 0;
            for( int i = 1; i < symbols.Length; ++i ) {
                // Shift and add new nibble.
                rv <<= 4;
                rv |= Convert.ToInt32(( (char)symbols[i].Data ).ToString(), 16);
            }

            // Return built char.
            return (char)rv;
        }

        // Hexadecimal escape processing.
        private object OctEscape(ParseState state, Token[] symbols) {
            // Loop over symbols, including first (which is the first octal character).
            int rv = 0;
            for( int i = 0; i < symbols.Length; ++i ) {
                // Shift and add nibble.
                rv <<= 4;
                rv |= Convert.ToInt32(( (char)symbols[i].Data ).ToString(), 8);
            }

            // Return built char.
            return (char)rv;
        }

        // Name grammar.
        private void GrammarNameNumber() {
            // Name.
            _Grammar["name"].Add(_Grammar["alpha"]).ReduceEvent += BuildName;
            _Grammar["name"].Add(_Grammar["name"] + _Grammar["alpha"]).ReduceEvent += BuildName;
            _Grammar["name"].Add(_Grammar["name"] + _Grammar["num"]).ReduceEvent += BuildName;

            // Number expressions.
            _Grammar["nums"].Add(_Grammar["num"]).ReduceEvent += BuildNumber;
            _Grammar["nums"].Add(_Grammar["nums"] + _Grammar["num"]).ReduceEvent += BuildNumber;
        }

        // Name building.
        private object BuildName(ParseState state, Token[] symbols) {
            // Check token length (for production).
            if( symbols.Length > 1 )
                return (string)symbols[0].Data + (char)symbols[1].Data;

            // Return single-character name.
            return ( (char)symbols[0].Data ).ToString();
        }

        // Number building for number expressions.
        private object BuildNumber(ParseState state, Token[] symbols) {
            // Check token length (for production).
            if( symbols.Length > 1 )
                // Is a follow.
                return (int)symbols[0].Data * 10 + Convert.ToInt32(( (char)symbols[1].Data ).ToString(), 10);

            // Is initial.
            return Convert.ToInt32(( (char)symbols[0].Data ).ToString(), 10);
        }

        // Parse the input regex (delegate to singleton parse.
        public static Tree Parse(string data, char flags, bool isnameexpr, Dictionary<string, Tree> namedre) {
            // Use singleton object to parse the RE.
            if( SINGLETON == null )
                SINGLETON = new RegExParser();
            return SINGLETON.DoParse(data, flags, isnameexpr, namedre);
        }

        // Instance parser.
        private Tree DoParse(string data, char flags, bool isnameexpr, Dictionary<string, Tree> namedre) {
            // Initialize lexer and parser, cloning passed named regular expression set.
            RELexer lexer = new RELexer(data, flags, isnameexpr);
            Parser parser = _Grammar.Parser;
            parser.Tag = namedre != null ? new Dictionary<string, Tree>(namedre) : new Dictionary<string, Tree>();

            // Parse the regex and return root node.
            return (Tree)parser.Parse(lexer.LexerCallback);
        }

    }

    // Lexer state helper.
    internal class RELexer {

        // Special characters.
        private static string SPECIAL = "\\|*+?{}-.[]()";

        // Data.
        private string _Data;
        private int _Position = -1;
        private char _Flags;
        private bool _IsNameExpr;

        // Constructor.
        public RELexer(string data, char flags, bool isnameexpr) {
            // Check flags token.
            if( SPECIAL.Contains(flags) || Char.IsLetter(flags) || Char.IsDigit(flags) )
                throw new ArgumentException("Illegal flags character; must not be letter/digit/special character");

            // Initialize data.
            _Data = data;
            _Flags = flags;
            _IsNameExpr = isnameexpr;
        }

        // Lexer callback.
        public Token LexerCallback(Grammar gram, Parser parser) {
            // Check initial position.
            if( _Position == -1 ) {
                // Increment position to start and yield initial token if name expression.
                ++_Position;
                if( _IsNameExpr )
                    return gram["nameexprflag"];
            }

            // Check for end of input.
            if( _Position == _Data.Length )
                return gram.EOI;

            // Initialize process escape.
            bool escaped = false;
            while( true ) {
                // Fetch next character from grammar and dispatch on it.
                char next = _Data[_Position++];
                if( Char.IsLetter(next) ) {
                    // Check for escape.
                    if( escaped ) {
                        // Check for escape sequences (replacing them by the corresponding value).
                        // If escape sequence is not found, this falls through to deliver the character.
                        switch( next ) {

                            case 'a':
                            case 'A':
                                // C-esque escape sequence \a
                                return gram["char"] / '\a';

                            case 'b':
                            case 'B':
                                // C-esque escape sequence \b
                                return gram["char"] / '\b';

                            case 'f':
                            case 'F':
                                // C-esque escape sequence \f
                                return gram["char"] / '\f';

                            case 'n':
                            case 'N':
                                // C-esque escape sequence \n
                                return gram["char"] / '\n';

                            case 'r':
                            case 'R':
                                // C-esque escape sequence \r
                                return gram["char"] / '\r';

                            case 't':
                            case 'T':
                                // C-esque escape sequence \t
                                return gram["char"] / '\t';

                            case 'u':
                            case 'U':
                                // Unicode escape intro.
                                return gram["uniescintro"];

                            case 'v':
                            case 'V':
                                // C-esque escape sequence \v
                                return gram["char"] / '\v';

                            case 'x':
                            case 'X':
                                // Hexadecimal escape intro.
                                return gram["hexescintro"];

                        }
                    } else
                        // Is a normal letter.
                        return gram["alpha"] / next;
                } else if( Char.IsDigit(next) ) {
                    // Check for escape.
                    if( escaped )
                        // Octal escape intro.
                        return gram["octescintro"] / next;
                    else
                        // Is a number/digit.
                        return gram["num"] / next;
                } else if( !escaped ) {
                    // Process the following elements only when the character is not escaped.
                    if( next == _Flags )
                        // Is the flags letter.
                        return gram["flags"];
                    else if( next == '\\' ) {
                        // Check whether a character is actually following.
                        if( _Position == _Data.Length )
                            throw new ArgumentException("Trailing escape character at end of RegEx");

                        // Yes, fetch that.
                        escaped = true;
                        continue;
                    } else if( SPECIAL.Contains(next) )
                        // Is an operator token.
                        return gram[next.ToString()] / next;
                }

                // Is a generic character (or any other character, escaped).
                return gram["char"] / next;
            }
        }

    }

}
